/*
Copyright 2021 LuJun

Permission is hereby granted, free of charge, to any person obtaining a copy 
of this software and associated documentation files (the "Software"), to deal 
in the Software without restriction, including without limitation the rights 
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
copies of the Software, and to permit persons to whom the Software is furnished 
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in 
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

namespace lcc {

export namespace express {

const Express = require('express');
const proxy = require('express-http-proxy');
const cors = require('cors');

const TAG = "lcc/network/http/express-preset.ts";

/**
 * @zh
 * 创建空Express
 */
export function createEmptyExpress(){
	return Express();
}

/**
 * @zh
 * 创建路由
 */
export function createRouter(){
	return Express.Router();
}

/**
 * @zh
 * 文件下载默认最大过期时间
 */
export let FILEDOWNLOAD_MAXAGE = 2592000000;

/**
 * @zh
 * 文件下载对象
 */
export interface FileDownload {
    /**
     * @zh
     * URL路径
     */
    urlPath?:string;

    /**
     * @zh
     * 文件路径
     */
    filePath:string;

    /**
     * @zh
     * 过期时间
     */
    maxAge?:number;
}

/**
 * @zh
 * 创建文件Express
 * 
 * @param paths 路径或配置数组
 */
export function createFilesExpress(...paths:(string|FileDownload)[]){
	let pExpress = Express();

	pExpress.use(cors()); 
	for (let path of paths){
        let fileDownload:FileDownload;
        if(typeof path == 'string'){
            fileDownload = {
                filePath : path,
            }
        }else{
            fileDownload = path;
        }
		pExpress.use(fileDownload.urlPath || '/', Express.static(fileDownload.filePath, {
            maxAge : fileDownload.maxAge || FILEDOWNLOAD_MAXAGE,
        })); 
	}

	// catch 404 and forward to error handler
	pExpress.use((req, res, next)=>{
		res.status(404);
		res.send('File Not Found');
	});

	// error handler
	pExpress.use(function(err, req, res, next) {
		// set locals, only providing error in development
		res.locals.message = err.message;
		res.locals.error = req.app.get('env') === 'development' ? err : {};
	
		// render the error page
		res.status(err.status || 500);
		res.send('Error');
	});
	
	return pExpress;
}

/**
 * @zh
 * 创建代理express
 * 
 * @param selectProxyHost 选择代理主机 originalUrl 原始URL， query 查询集合
 */
export function createProxyExpress(selectProxyHost:string|string[]|((originalUrl:string, query:any)=>string), forwardPath?:(originalUrl:string)=>string){
    let pExpress = Express();

	pExpress.use(cors());
    pExpress.use('*', proxy((req:any, res:any)=>{
        if(typeof selectProxyHost == 'string'){
            return selectProxyHost;
        }else if(typeof selectProxyHost == 'function'){
            let host = selectProxyHost(req.originalUrl, req.query);
            if(!host){
                res.status(500).json({ error: 'selectProxyHost error' });
            }else{
                return host;
            }
        }else{
            return math.randomElement(selectProxyHost);
        }
    },{
        proxyReqPathResolver : (req:any, res:any)=>{
            if(forwardPath){
                return forwardPath(req.originalUrl);
            }else{
                return req.originalUrl;
            }
        },
        proxyReqOptDecorator: (proxyReq:any, srcReq:any) => {
            proxyReq.headers['host'] = srcReq.host;
            proxyReq.headers['x-real-ip'] = srcReq.socket.remoteAddress;
            let srcXFF = srcReq.headers['x-forwarded-for'];
            proxyReq.headers['x-forwarded-for'] = (srcXFF ? (srcXFF + ",") : "") + srcReq.ip;
            return proxyReq;
        }
    }));
    
	return pExpress;
}

}

}
